#ifndef IMAGE_H
#define IMAGE_H
/**
 * \file Image.h
 * \brief Définit une Image
 * \author Romain Charbit
 *
 */
#include <GL/glut.h>
#include "Matrice.h"

class vecteur;
class Pixel;
class Histogramme;
class vecteur;
class Masque;

struct FiltreLineaire{
	int taillex,tailley;
	float *coef;
} ;

/*! \class Image
* \brief Classe Image RGB
*
*  La classe permet l'utilisation d'Image RGB
*/

class Image
{
public :

friend class InpaintingThese;

/*!
 *  \brief Constructeur
 *
 *  Constructeur de la classe Image
 *
 *  \param l : largeur de l'image
 *  \param h : hauteur de l'image
 */
	Image( int l=0, int h=0 );
/*!
 *  \brief Destructeur
 *
 *  Destructeur de la classe Image
 */
	~Image();
/*!
 *  \brief Ecrit un pixel
 *
 *  Methode qui permet d'écrire la valeur d'un pixel dans l'image
 *
 *  \param x : coordonnées en x du pixel a remplir
 *  \param y : coordonnées en y du pixel a remplir
 *  \param couleur : couleur du pixel a remplir
 *  \return void
 */
	void EcritPixel(int x, int y, Pixel couleur);
/*!
 *  \brief Lit un pixel
 *
 *  Methode qui permet de lire la valeur d'un pixel dans l'image
 *
 *  \param x : coordonnées en x du pixel a lire
 *  \param y : coordonnées en y du pixel a lire
 *  \return Retourne la couleur du pixel
 */
	Pixel LitPixel(int x, int y);
/*!
 *  \brief Filtre l'image
 *
 *  Methode qui permet de filtrer l'image en fonction du filtre passé en parametre. Creer le buffer data.
 *
 *  \param fl : filtre utilisé
 *  \return Retourne le résultat du filtrage
 */
	Image* FiltrageLineaire(FiltreLineaire *fl);

/*!
 *  \brief Filtre l'image
 *
 *  Methode qui permet de filtrer l'image en fonction du filtre passé en parametre en coordonnées x,y.
 *
 *  \param fl : filtre utilisé
 *  \param x : coordonnée x 
 *  \param y : coordonnée x
 *  \return Retourne le Pixel résultat du filtrage
 */

	Pixel FiltrageLineaire(FiltreLineaire *fl,int x,int y);
/*!
 *  \brief Calcul le laplacien
 *
 *  Methode qui permet de calculer le laplacien de l'image. Creer le buffer indirectement (le filtrage le fait).
 *
 *  \return void
 */
 
	Image* Laplacien();
	Pixel Laplacien(int x,int y);

/*!
 *  \brief Calcule la composante en x du gradient
 *
 *  Methode qui permet de calculer le gradient en x de l'image. Creer le buffer indirectement (le filtrage le fait).
 *
 *  \return Image*
 */
 
 	Image* Gradientx();
	Pixel Gradientx(int x,int y);

/*!
 *  \brief Calcule la composante en y du gradient
 *
 *  Methode qui permet de calculer le gradient en y de l'image. Creer le buffer indirectement (le filtrage le fait).
 *
 *  \return Image*
 */

	Image* Gradienty();
	Pixel Gradienty(int x,int y);
	
/*!
 *  \brief Calcule le vecteur gradient du canal donné, pour le pixel donné
 *
 *  Utilise SobelX et SobelY. Besoin de ce format pour l'inpainting de la thèse
 *  \param _x : abscisse du pixel
 *  \param _y : ordonnée du pixel
 *  \param _canal : canal de couleur (0,1,2)
 *  \param _mat : la matrice à remplir (si NULL, elle sera créée)
 *  \return pointeur vers la matrice 2 lignes 1 colonne (vecteur) calculée
 */	
	Matrice * computeGradient ( int _x, int _y, int _canal = 0,
		Matrice * _mat = NULL );
	
	
/*!
 *  \brief Calcule (nabla I) . (nabla I transposée)
 *
 *  Stou
 *  \param _x : abscisse du pixel
 *  \param _y : ordonnée du pixel
 *  \param _canal : canal de couleur (0,1,2)
 *  \param _res : la matrice résultante (créée si NULL)
 *  \return pointeur vers la matrice 2x2 calculée
 */		
	Matrice * nablaInablaIT ( int _x, int _y, int _canal = 0,
		Matrice * _res = NULL );
	
/*!
 *  \brief Calcule la somme des nablaInablaIT sur tous les canaux de couleur
 *
 *  Stou
 *  \param _x : abscisse du pixel
 *  \param _y : ordonnée du pixel
 *  \param _res : la matrice résultante (créée si NULL)
 *  \param _canaux : le nombre de canaux (accèdera aux canaux 0 à _canaux-1)
 *  \return pointeur vers la matrice 2x2 calculée
 */	
	Matrice * sommeNablaInablaIT ( int _x, int _y, Matrice * _res = NULL,
	int _canaux = 3 );

/*!
 *  \brief Calcule la "smoothness" de l'image au pixel (x,y)
 *
 *  Methode qui permet de calculer la smoothness de l'image au pixel (x,y)
 *
 *	\param x : coordonnée en x du pixel dont on calcule la smoothness
 *	\param y : coordonnée en y du pixel dont on calcule la smoothness
 *
 *  \return vecteur*
 */

	vecteur* ComputeSmoothness( int x, int y,Image* laplacien );

	/*!
 *  \brief Effectue 2 iterations de diffusion anisotropique sur l'image.
 *
 *  Methode qui passe un "filtre anisotropique" sur l'image
 *
 *  \return Image*
 */

	Image* DiffusionAnisotrope (Masque* m);
	
/*!
 *  \brief Renvoie la matrice du tenseur de structure calculé au pixel (_x,_y) de l'image
 *
 *  Methode qui calcule le tenseur de structure calculé au pixel (_x,_y) de l'image
 *  \param _x : abscisse du pixel dont on veut le tenseur
 *  \param _y : ordonnée du pixel dont on veut le tenseur
 *  \param _canal : canal sur lequel on calcule le tenseur ( r,v ou b => 0,1 ou 2 )
 *  \return Renvoie la matrice du tenseur de structure au pixel (_x,_y) de l'image
 */

	Matrice* computeTenseurStructure ( int _x, int _y, int _canal );
	
/*!
 *  \brief Renvoie la matrice du tenseur de diffusion calculé au pixel (_x,_y) de l'image
 *
 *  Methode qui calcule le tenseur de diffusion calculé au pixel (_x,_y) de l'image
 *  \param _x : abscisse du pixel dont on veut le tenseur
 *  \param _y : ordonnée du pixel dont on veut le tenseur
 *  \param _canal : canal sur lequel on calcule le tenseur ( r,v ou b => 0,1 ou 2 )
 *  \return Renvoie la matrice du tenseur de diffusion au pixel (_x,_y) de l'image
 */

	Matrice* computeTenseurDiffusion ( int _x, int _y, int _canal );

/*!
 *  \brief calcule la matrice Hessienne 2x2 pour le canal i du pixel (x;y)
 *
 *  Matrice Hessienne, cf définition "3.5.2 Using a spatial discretization of the Hessian", P103 de la thèse.
 *
 *  \param _x : abscisse du pixel
 *  \param _y : ordonnée du pixel
 *  \param _canal : canal de couleur (0,1,2)
 *  \param _mat : la matrice à remplir (si NULL, elle sera créée)
 *  \return pointeur vers la matrice calculée
 */
	Matrice* computeHessienne ( int _x, int _y, int _canal = 0,
		Matrice * _mat = NULL );

/*!
 *  \brief Copie une image
 *
 *  Methode qui renvoi une copie de l'image
 *
 *  \param out image cible (sera créée si NULL)
 *  \return Retourne l'image copiée
 */
	Image* CopierImage ( Image * out = NULL );
	
/*!
 *  \brief Effectue un blit
 *
 *  Copie une zone rectangulaire d'une image sur l'image actuelle.
 *
 *  \param im image à copier
 *  \return Retourne l'image copiée
 */	
	void BlitFrom ( Image * im, int xmin, int xmax, int ymin, int ymax );
/*!
 *  \brief Transforme l'image en GLubyte
 *
 *  Methode qui permet de transformer l'image dans un format affichable par OpenGL
 *
 *  \return void
 */
	void toSprite();
/*!
 *  \brief Afficher l'image
 *
 *  Methode qui permet d'afficher le sprite de l'image, la methode toSprite doit être appelé préalablement
 *
 *  \return void
 */
	void Afficher();
/*!
 *  \brief Charge une image PPM
 *
 *  Charge une Image PPM dans le pointeur data qui est constitué de largeur*hauteur pixels 24 bits (RVB)
 *
 *  \param nom_fichier : nom du fichier à charger
 *
 *  \return Renvoie 0 si le chargement c'est bien passée, -1 sinon
 */
	int chargePPM (const char *nom_fichier);
/*!
 *  \brief Sauve une image PPM
 *
 *  Enregistre sur le disque l'image au format PPM
 *
 *  \param nom_fichier : nom du fichier de sauvegarde
 *  
 *  \return Renvoie 0 si la sauvegarde c'est bien passée, -1 sinon
 */
	int sauvePPM (const char *nom_fichier);
/*!
 *  \brief Acceseur largeur
 *
 *  Renvoie la largeur de l'image
 *  
 *  \return Renvoie la largeur de l'image
 */
	int getL(){return largeur;}
/*!
 *  \brief Acceseur hauteur
 *
 *  Renvoie la hauteur de l'image
 *  
 *  \return Renvoie la hauteur de l'image
 */
	int getH(){return hauteur;}
	
	vecteur* computeIsophoteDirection(int _x,int _y,Image* grX,Image* grY);

	Pixel operator()(const int x, const int y);

private:
	int	largeur; /*!<Largeur de l'image*/
	int	hauteur; /*!<Hauteur de l'image*/
	Pixel* data; /*!<Données de l'image au format largeur*hauteur, chaque composante étant un pixel(R,G,B)*/
	GLubyte* sprite; /*!<Données de l'image au format largeur*hauteur*3, R,V,B,R,V,B,R,V...*/
};

#endif
